/*互斥锁是完全互斥的，但是有很多实际的场景下是读多写少的，当我们并发的去读取一个资源不涉及资源修改的时候是没有必要加锁的，
这种场景下使用读写锁是更好的一种选择。读写锁在Go语言中使用sync包中的RWMutex类型。
读写锁分为两种：读锁和写锁。当一个goroutine获取读锁之后，其他的goroutine如果是获取读锁会继续获得锁，如果是获取写锁就会等待；
当一个goroutine获取写锁之后，其他的goroutine无论是获取读锁还是写锁都会等待。*/

package main

import (
	"fmt"
	"sync"
	"time"
)

var x = 10
var wbg sync.WaitGroup

var lobck sync.Mutex    // 值类型，不需要初始化
var rwlock sync.RWMutex // 值类型，不需要初始化

func wribte() {
	//rwlock.Lock() // 写锁都用Lock
	lobck.Lock()
	time.Sleep(1 * time.Millisecond) // 模拟写耗时1毫秒
	x = x + 1
	//rwlock.Unlock()
	lobck.Unlock()
	wbg.Done()

}
func rebad() {
	//rwlock.RLock() // 读锁用RLock
	lobck.Lock()
	time.Sleep(time.Millisecond) // 模拟读耗时1毫秒
	//fmt.Printf("x 现在的值是：%d\n",x)
	//rwlock.RUnlock()
	lobck.Unlock()
	wbg.Done()

}
func main() {
	// 统计开始时间
	time1 := time.Now()
	// 开10个协程写
	for i := 0; i < 10; i++ {
		wbg.Add(1)
		go wribte()
	}
	// 开1000个协程读
	for i := 0; i < 1000; i++ {
		wbg.Add(1)
		go rebad()
	}

	wbg.Wait()
	fmt.Println("x最终值为：", x)
	// 统计结束时间
	time2 := time.Now()
	fmt.Println(time2.Sub(time1)) // 结束时间-开始时间

	// 使用读写锁:15.387426ms
	// 使用互斥锁：1.26868106s
}
